package netTools.mail;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;

import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSAlgorithm;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.util.Store;

public class StrongMail {

	private String STRONGBOX_P12;
	private String mailAddress;
	private Session session;
	private String logFile;
	private SMIMEEnvelopedGenerator encGen;
	private SMIMESignedGenerator signGen;
	private boolean logMailSent;

	public StrongMail(String mailAddress,String logPath,String ksPass,String smtpServer) throws IOException{
		logMailSent = false;
		this.mailAddress = mailAddress;
		String mailHost = mailAddress.split("@")[1];
		String mailUser = mailAddress.split("@")[0];

		logFile = logPath;
		STRONGBOX_P12 = mailUser+".p12";
		try {
			Security.addProvider(new BouncyCastleProvider());
			KeyStore ks = KeyStore.getInstance("PKCS12");
			InputStream is = new FileInputStream(STRONGBOX_P12);
			ks.load(is, ksPass.toCharArray());
			is.close();
			//retrieval of infos
			String alias = ks.aliases().nextElement();
			PrivateKey pk = (PrivateKey)ks.getKey(alias, ksPass.toCharArray());
			Certificate certArray[] = ks.getCertificateChain(alias);
			List<Certificate> certList = new ArrayList<Certificate>();
			for(int i=0;i<certArray.length;i++)
				certList.add(certArray[i]);
			Store certs = new JcaCertStore(certList);
			//creation of signature generator
			signGen = makeSignGen((X509Certificate) certArray[0], pk, certs);

			//creation of enc generator (recipient is the sender himself)
			X509Certificate rcptCer = (X509Certificate) certArray[0];
			encGen = this.makeEncGen(rcptCer);


			//setting of mail properties
			Properties props = new Properties();
			props.setProperty("mail.debug", "false");
			props.setProperty("mail.smtp.starttls.enable", "true");
			props.setProperty("mail.transport.protocol", "smtp");
			props.setProperty("mail.smtp.host", smtpServer);
			props.setProperty("mail.host", mailHost);
			props.setProperty("mail.smtp.port", "587");
			props.setProperty("mail.smtp.auth", "true");
			props.setProperty("mail.user", mailUser);

			session = Session.getDefaultInstance(props, 
					new EmailAuthenticator(mailUser,ksPass));

		} catch (KeyStoreException e) {
			//
		} catch (NoSuchAlgorithmException e) {
			throw new IOException(e.getMessage());
		} catch (CertificateException e) {
			throw new IOException(e.getMessage());
		} catch (UnrecoverableKeyException e) {
			throw new IOException(e.getMessage());
		} catch (OperatorCreationException e) {
			//
		}
	}

	public synchronized void sendLoggerAlarm(){
		if(!logMailSent){ //log mail is just sent one time
			try{
				JceCMSContentEncryptorBuilder encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC, 128);
				encryptor.setProvider("BC");

				String message = "<html><body><h1>Could not contact logger server!</h1><br>" +
				"<h2>Be sure to check logger server, an DoS attack could be in place.\n" +
				"Following you'll find a copy of logs so far</h2><br>";

				message += logToString();
				message += "</body></html>";

				MimeBodyPart body = new MimeBodyPart();
				body.setContent(message,"text/html");
				MimeBodyPart encryptedBody = encGen.generate(body, encryptor.build());

				Multipart signedMulti = signGen.generate(encryptedBody);
				MimeMessage smime = new MimeMessage(session);
				smime.setContent(signedMulti);
				smime.addRecipient(Message.RecipientType.TO, new InternetAddress(
						mailAddress));
				smime.setSubject("Strongbox message[ALERT]");

				Transport transport = session.getTransport();
				transport.connect();
				transport.sendMessage(smime, smime.getRecipients(Message.RecipientType.TO));
				transport.close();

				logMailSent = true;
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	public void sendIPAlarm(String bannedIP){
		try{
			JceCMSContentEncryptorBuilder encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC, 128);

			encryptor.setProvider("BC");
			String message = "<html><body>IP <h1>"+bannedIP+"</h1> was just banned</body></html>";
			MimeBodyPart body = new MimeBodyPart();
			body.setContent(message,"text/html");
			MimeBodyPart encryptedBody = encGen.generate(body, encryptor.build());
			Multipart signedMulti = signGen.generate(encryptedBody);

			MimeMessage smime = new MimeMessage(session);
			smime.setContent(signedMulti);
			smime.addRecipient(Message.RecipientType.TO, new InternetAddress(
					mailAddress));
			smime.setSubject("Strongbox message[IP BANNED]");

			Transport transport = session.getTransport();
			transport.connect();
			transport.sendMessage(smime, smime.getRecipients(Message.RecipientType.TO));
			transport.close();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

	public static void main(String[] args) throws IOException{
		StrongMail sm = new StrongMail("strongbox@email.it","/home/pasquale/workspace/strongbox!_server/logs/2011-09-03-log.txt",
				"hellMail02","smtp.email.it");
		sm.sendIPAlarm("192.168.1.5");
	}

	private SMIMEEnvelopedGenerator makeEncGen(X509Certificate cert) throws CertificateEncodingException, IllegalArgumentException, OperatorCreationException{
		SMIMEEnvelopedGenerator encGen = new SMIMEEnvelopedGenerator();
		JceCMSContentEncryptorBuilder encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC, 128);
		encryptor.setProvider("BC");
		encGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC"));

		return encGen;
	}

	private SMIMESignedGenerator makeSignGen(X509Certificate cert,PrivateKey pk,Store certChain) throws CertificateEncodingException, OperatorCreationException{
		SMIMESignedGenerator signGen = new SMIMESignedGenerator();
		signGen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build(
				"SHA256withRSA", pk, cert));
		signGen.addCertificates(certChain);
		return signGen;
	}

	private String logToString(){
		String log = "";
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					new FileInputStream(logFile)));
			log += "<table>";
			String read = null;

			while((read = reader.readLine())!=null)
				log += ("<tr><td>"+read+"</td></tr>");

			log += "</table>";
			reader.close();
		} catch (IOException e) {
		}

		return log;
	}

}
